﻿#region Disclaimer/Info
///////////////////////////////////////////////////////////////////////////////////////////////////
// MetaCollection
// 
// MetaCollection is a system to provide a standard structure, permissions and metadata service
// for content organization.
//
// This project is hosted at Google Code at http://code.google.com/p/metacollection/
//
// This project is licensed under the BSD license.  See the License.txt file for more information.
///////////////////////////////////////////////////////////////////////////////////////////////////
#endregion

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Globalization;
using System.IO;
using System.Xml;
using MetaCollection.Framework.Model;

namespace MetaCollection.Framework.Configuration
{
	/// <summary>
	/// The Configuration Section for a Collection.
	/// </summary>
	public partial class CollectionConfigurationSection : global::System.Configuration.ConfigurationSection
	{ }

	/// <remarks>The generator does not include the AddItemName.  Because of this after generation the ConfigurationCollection attribute should be removed from the generated code.</remarks>
	[global::System.Configuration.ConfigurationCollection(typeof(global::MetaCollection.Framework.Configuration.ItemReferenceElement), AddItemName = "root", CollectionType = global::System.Configuration.ConfigurationElementCollectionType.AddRemoveClearMap)]
	public partial class ItemReferenceCollection : global::System.Configuration.ConfigurationElementCollection
	{}
	/// <remarks>The generator does not include the AddItemName.  Because of this after generation the ConfigurationCollection attribute should be removed from the generated code.</remarks>
	[global::System.Configuration.ConfigurationCollection(typeof(global::MetaCollection.Framework.Configuration.ProviderReferenceElement), AddItemName = "provider", CollectionType = global::System.Configuration.ConfigurationElementCollectionType.AddRemoveClearMap)]
	public partial class ProviderReferenceCollection : global::System.Configuration.ConfigurationElementCollection
	{}
	/// <remarks>The generator does not include the AddItemName.  Because of this after generation the ConfigurationCollection attribute should be removed from the generated code.</remarks>
	[global::System.Configuration.ConfigurationCollection(typeof(global::MetaCollection.Framework.Configuration.TypeReferenceElement), AddItemName = "reference", CollectionType = global::System.Configuration.ConfigurationElementCollectionType.AddRemoveClearMap)]
	public partial class TypeReferenceCollection : global::System.Configuration.ConfigurationElementCollection
	{}

	/// <summary>
	/// The Provider Reference Element is used to provide a formal configuration format for a provider type record when used
	/// by the Resource Provider class for creating Provider Instances.
	/// </summary>
	public partial class ProviderReferenceElement : global::System.Configuration.ConfigurationElement
	{
		private const string TextDataNodeName = "textConfig";
		[ConfigurationProperty(TextDataNodeName)]
		public string Text
		{
			get
			{
				return (string)base[TextDataNodeName];
			}
			set
			{
				base[TextDataNodeName] = value;
			}
		}

		/// <summary>
		/// Writes the contents of this configuration element to the configuration file when implemented in a derived class.
		/// </summary>
		/// <param name="writer">The <see cref="T:System.Xml.XmlWriter"/> that writes to the configuration file.</param>
		/// <param name="serializeCollectionKey">true to serialize only the collection key properties; otherwise, false.</param>
		/// <returns>
		/// true if any data was actually serialized; otherwise, false.
		/// </returns>
		/// <exception cref="T:System.Configuration.ConfigurationErrorsException">
		/// The current attribute is locked at a higher configuration level.
		/// </exception>
		protected override bool SerializeElement(System.Xml.XmlWriter writer, bool serializeCollectionKey)
		{
			if (writer != null)
			{
				foreach (ConfigurationProperty configurationProperty in Properties)
				{
					string name = configurationProperty.Name;
					TypeConverter converter = configurationProperty.Converter;
					string propertyValue = converter.ConvertToString(base[name]);

					if (name == TextDataNodeName)
					{
						if (!String.IsNullOrEmpty(propertyValue))
							writer.WriteCData(propertyValue);
					}
					else if (typeof(ConfigurationElement).IsAssignableFrom(configurationProperty.Type))
					{
						typeof(ConfigurationElement).GetMethod("SerializeElement").Invoke(base["name"], new object[] { writer, false });
					}
					else
					{
						writer.WriteAttributeString(name, propertyValue);
					}
				}
			}
			return true;
		}

		/// <summary>
		/// Reads XML from the configuration file.
		/// </summary>
		/// <param name="reader">The <see cref="T:System.Xml.XmlReader"/> that reads from the configuration file.</param>
		/// <param name="serializeCollectionKey">true to serialize only the collection key properties; otherwise, false.</param>
		/// <exception cref="T:System.Configuration.ConfigurationErrorsException">
		/// The element to read is locked.
		/// - or -
		/// An attribute of the current node is not recognized.
		/// - or -
		/// The lock status of the current node cannot be determined.
		/// </exception>
		protected override void DeserializeElement(System.Xml.XmlReader reader, bool serializeCollectionKey)
		{
			if (reader == null)
				throw new ArgumentNullException("reader");
			foreach (ConfigurationProperty configurationProperty in Properties)
			{
				string name = configurationProperty.Name;
				if (name == TextDataNodeName)
				{
					string contentString = reader.ReadString();
					base[name] = contentString.Trim();
				}
				else
				{
					string attributeValue = reader.GetAttribute(name);
					base[name] = attributeValue;
				}
			}
			reader.ReadEndElement();
		}

		/// <summary>
		/// Handles the unrecognized element.
		/// </summary>
		/// <param name="elementName">Name of the element.</param>
		/// <param name="reader">The reader.</param>
		/// <returns>[true] if the element was not recognized.</returns>
		private global::System.Boolean HandleUnrecognizedElement(global::System.String elementName, XmlReader reader)
		{
			string attributeValue = reader.GetAttribute(elementName);
			base[elementName] = attributeValue;
			return false;
		}
	}

	/// <summary>
	/// Type of Repository Interface this Reference uses
	/// </summary>
	public enum RepositoryReferenceType
	{
		Item,
		Resource,
		Model,
		Audit,
		Index
	}

	/// <summary>
	/// The Type Reference Element is used to specify a type that needs to be loaded.  This element
	/// allows sub nodes which can be used to hold configuration data for the type that is going to
	/// be loaded.  When the type is instantiated this data is made available.
	/// </summary>
	public partial class TypeReferenceElement : global::System.Configuration.ConfigurationElement
	{
		private const string TextDataNodeName = "dataConfig";
		[ConfigurationProperty(TextDataNodeName)]
		public string ConfigData
		{
			get
			{
				return (string)base[TextDataNodeName];
			}
			set
			{
				base[TextDataNodeName] = value;
			}
		}

		/// <summary>
		/// Writes the contents of this configuration element to the configuration file when implemented in a derived class.
		/// </summary>
		/// <param name="writer">The <see cref="T:System.Xml.XmlWriter"/> that writes to the configuration file.</param>
		/// <param name="serializeCollectionKey">true to serialize only the collection key properties; otherwise, false.</param>
		/// <returns>
		/// true if any data was actually serialized; otherwise, false.
		/// </returns>
		/// <exception cref="T:System.Configuration.ConfigurationErrorsException">
		/// The current attribute is locked at a higher configuration level.
		/// </exception>
		protected override bool SerializeElement(System.Xml.XmlWriter writer, bool serializeCollectionKey)
		{
			if (writer != null)
			{
				foreach (ConfigurationProperty configurationProperty in Properties)
				{
					string name = configurationProperty.Name;
					TypeConverter converter = configurationProperty.Converter;
					string propertyValue = converter.ConvertToString(base[name]);

					if (name == TextDataNodeName)
					{
						if (!String.IsNullOrEmpty(propertyValue))
							writer.WriteCData(propertyValue);
					}
					else if (typeof(ConfigurationElement).IsAssignableFrom(configurationProperty.Type))
					{
						typeof(ConfigurationElement).GetMethod("SerializeElement").Invoke(base["name"], new object[] {writer, false} );
					}
					else
					{
						writer.WriteAttributeString(name, propertyValue);
					}
				}
			}
			return true;
		}

		/// <summary>
		/// Reads XML from the configuration file.
		/// </summary>
		/// <param name="reader">The <see cref="T:System.Xml.XmlReader"/> that reads from the configuration file.</param>
		/// <param name="serializeCollectionKey">true to serialize only the collection key properties; otherwise, false.</param>
		/// <exception cref="T:System.Configuration.ConfigurationErrorsException">
		/// The element to read is locked.
		/// - or -
		/// An attribute of the current node is not recognized.
		/// - or -
		/// The lock status of the current node cannot be determined.
		/// </exception>
		protected override void DeserializeElement(System.Xml.XmlReader reader, bool serializeCollectionKey)
		{
			if (reader == null)
				throw new ArgumentNullException("reader");
			foreach (ConfigurationProperty configurationProperty in Properties)
			{
				string name = configurationProperty.Name;
				if (name != TextDataNodeName)
				{
					string attributeValue = reader.GetAttribute(name);
					base[name] = attributeValue;
				}
			}

			string contentString = reader.ReadString();
			base[TextDataNodeName] = contentString.Trim();

			// calling reader.ReadString() will advance the reader to the end element. if we are on the end then we 
			// don't want to read another endelement or we will lose our place.
			if ((reader.NodeType & XmlNodeType.EndElement) == XmlNodeType.EndElement)
				reader.ReadEndElement();
		}

		/// <summary>
		/// Handles the unrecognized element.
		/// </summary>
		/// <param name="elementName">Name of the element.</param>
		/// <param name="reader">The reader.</param>
		/// <returns>[true] if the element was not recognized.</returns>
		private global::System.Boolean HandleUnrecognizedElement(global::System.String elementName, XmlReader reader)
		{
			string attributeValue = reader.GetAttribute(elementName);
			base[elementName] = attributeValue;
			return false;
		}
	}

	public static partial class Extension
	{
		/// <summary>
		/// Converts the Provider Reference into an IProviderType record
		/// </summary>
		/// <param name="providerReference">The provider reference.</param>
		/// <returns>An IProviderType record</returns>
		public static IProviderType ToProviderType(this ProviderReferenceElement providerReference)
		{
			ProviderType provider = new ProviderType();
			if (providerReference == null)
				return provider;

			provider.Name = providerReference.Name;
			provider.AssemblyName = providerReference.AssemblyName;
			provider.TypeName = providerReference.TypeName;
			provider.Config = providerReference.Text;
			return (IProviderType)provider;
		}

		/// <summary>
		/// Enumerates a collection of ProviderReferenceElements and returns IProviderType elements
		/// </summary>
		/// <param name="providerReferences">The provider references.</param>
		/// <returns>IProviderType Elements</returns>
		public static IEnumerable<IProviderType> ToProviderType(this IEnumerable<ProviderReferenceElement> providerReferences)
		{
			foreach (var reference in providerReferences)
			{
				yield return reference.ToProviderType();
			}
			yield break;
		}

		public static ProviderReferenceElement ToReference(this IProviderType providerType)
		{
			ProviderReferenceElement reference = new ProviderReferenceElement();
			if (providerType == null)
				return reference;
			reference.AssemblyName = providerType.AssemblyName;
			reference.Name = providerType.Name;
			reference.TypeName = providerType.TypeName;
			reference.Text = providerType.Config;
			return reference;
		}
	}
}
